﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="MainForm.cs" company="TechBits">
//   Copyright (c) TechBits. All rights reserved.
// </copyright>
// <author>
//   Leandro G. Vacirca
// </author>
// <summary>
//   Defines the MainForm type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace IntelliShortCut.UI.Forms
{
    using System;
    using System.Drawing;
    using System.Reflection;
    using System.Threading;
    using System.Windows.Forms;

    using Application;
    using Application.Helpers;
    using Data;
    using log4net;
    using Properties;

    /// <summary>
    /// The main window of the application.
    /// </summary>
    public partial class MainForm : Form
    {
        #region "Private Members"

        /// <summary>
        /// Logger interface.
        /// </summary>
        private static ILog _logger;

        #endregion

        #region "Constructor"

        /// <summary>
        /// Initializes a new instance of the <see cref="MainForm"/> class.
        /// </summary>
        public MainForm()
        {            
            InitializeComponent();

            // Get access to the logger
            _logger = LogManager.GetLogger(typeof(MainForm));

            ShortcutApl.Instance.OnShorcutsChanged += OnShortcutsChanged;
            ShortcutApl.Instance.OnAutoCompletionModeChanged += OnAutoCompletionModeChanged;
            ApplicationConfiguration.OnAppSettingsChanged += OnAppSettingsChanged;
        }

        #endregion

        #region "UI Events"

        /// <summary>
        /// Load event.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The event parameters.</param>
        private void MainForm_Load(object sender, EventArgs e)
        {
            Text += string.Format(" [beta {0}] by Leandro G. Vacirca", Assembly.GetExecutingAssembly().GetName().Version);
            InputTextBox.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
            InputTextBox.AutoCompleteSource = AutoCompleteSource.CustomSource;
            ShortCutIconPictureBox.Image = Resources.IS;
            ShowValidationStatus();
            LoadAutoCompleteList(AutoCompleteSource.CustomSource);
            CurrentDateTimer.Start();
            WindowsHelper.HideCaretCursor(InputTextBox.Handle);
            ShortcutApl.Instance.SetAutoCompletionMode(AutoCompletionModeEnum.All);
            Hide();
        }

        /// <summary>
        /// FormClosing event.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The event parameters.</param>
        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            TrayNotifyIcon.Dispose();            
            ShortcutApl.Instance.Commit();
        }

        /// <summary>
        /// Reloads the autocompletion list when a new shortcut has been added or removed.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The event parameters.</param>
        private void OnShortcutsChanged(object sender, ShortcutEventArgs e)
        {
            try
            {
                LoadAutoCompleteList(AutoCompleteSource.CustomSource);
            }
            catch (Exception ex)
            {
                _logger.Error(ex);
            }
        }

        /// <summary>
        /// Shows the current mode on the tray icon tooltip.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The event parameters.</param>
        private void OnAutoCompletionModeChanged(object sender, ShortcutEventArgs e)
        {
            try
            {
                TrayNotifyIcon.Text = string.Format("IntelliShortCut running ... (Current mode: {0})", e.AutoCompletionMode);
            
                var mode = ShortcutApl.Instance.AutoCompletionMode.Equals(AutoCompletionModeEnum.List)
                               ? ShortcutApl.Instance.PreviousAutoCompletionMode
                               : ShortcutApl.Instance.AutoCompletionMode;
                ModeLinkLabel.Text = mode.ToString().ToLower();
            }
            catch (Exception ex)
            {
                _logger.Error(ex);
            }
        }

        /// <summary>
        /// Executes the application associated to the shortcut.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The event parameters.</param>
        private void InputTextBox_KeyDown(object sender, KeyEventArgs e)
        {
            try
            {
                switch (e.KeyCode)
                {
                    // Executes the current input entry
                    case Keys.Enter:
                        {
                            Hide();                            
                            ShortcutApl.Instance.ExecuteShortcut(InputTextBox.Text);
                            InputTextBox.Text = string.Empty;
                            
                            break;
                        }
                        
                    // Changes 
                    case Keys.Down:
                        {
                            if (ShortcutApl.Instance.AutoCompletionMode.Equals(AutoCompletionModeEnum.Browser))
                            {
                                return;
                            }

                            ShortcutApl.Instance.SetAutoCompletionMode(AutoCompletionModeEnum.List);
                            LoadAutoCompleteList(AutoCompleteSource.CustomSource);
                            SendKeys.Send(".");
                            
                            break;
                        }

                    case Keys.Escape:
                        {
                            Hide();
                            InputTextBox.Text = string.Empty;
                            break;
                        }

                    case Keys.Right:
                        {
                            // Checks if the current mode is file or folder browser
                            if (ShortcutApl.Instance.AutoCompletionMode.Equals(AutoCompletionModeEnum.Browser))
                            {
                                var inputText = InputTextBox.Text;

                                if (inputText.Length == 1)
                                {
                                    SendKeys.Send(":\\");
                                }
                                else
                                {
                                    if (!inputText.EndsWith("\\"))
                                    {
                                        InputTextBox.SelectionStart = InputTextBox.Text.Length;
                                        SendKeys.Send("\\");
                                    }
                                }

                                InputTextBox.Focus();
                            }

                            break;
                        }

                    case Keys.Left:
                        {
                            // Checks if the current mode is file or folder browser
                            if (ShortcutApl.Instance.AutoCompletionMode.Equals(AutoCompletionModeEnum.Browser))
                            {
                                var text = InputTextBox.Text;

                                if (text.Split('\\').Length > 0)
                                {
                                    text = text.Substring(0, text.LastIndexOf("\\"));
                                    InputTextBox.Text = text;
                                    InputTextBox.SelectionStart = InputTextBox.Text.Length;
                                    InputTextBox.Focus();
                                }
                            }
                        }

                        break;
                }
            }
            catch (Exception ex)
            {
                _logger.Error(string.Format("An error ocurred while trying to execute a shortcut.\nDetails: {0}", ex.Message));
            }
        }

        /// <summary>
        /// Shows the icon of the shortcut.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The event parameters.</param>
        private void InputTextBox_TextChanged(object sender, EventArgs e)
        {
            try
            {
                SetAutoCompletionMode(InputTextBox.Text, true);
                ShortCutIconPictureBox.Image = ShortcutApl.Instance.GetShortcutIcon(InputTextBox.Text);
            }
            catch (Exception exception)
            {
                _logger.Error(exception);
            }
        }

        /// <summary>
        /// Shows the form.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The event parameters.</param>
        private void ShowSystemHotkey_Pressed(object sender, EventArgs e)
        {
            if (Visible)
            {
                return;
            }

            Show();
            ShowValidationStatus();          
            WindowState = FormWindowState.Normal;
            InputTextBox.Focus();
            WindowsHelper.HideCaretCursor(InputTextBox.Handle);
        }

        /// <summary>
        /// Hides the form.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The event parameters.</param>
        private void HideSystemHotkey_Pressed(object sender, EventArgs e)
        {
            if (!Visible)
            {
                return;
            }

            Hide();
        }

        /// <summary>
        /// Shows the current autocompletion mode.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The event parameters.</param>
        private void ShowModeHotkey_Pressed(object sender, EventArgs e)
        {
            ShowMessage(string.Format("Current mode: {0}", ShortcutApl.Instance.AutoCompletionMode), Color.Turquoise, 1500);
        }

        /// <summary>
        /// Shows the shortcuts editor.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The event parameters.</param>
        private void ShowEditorHotkey_Pressed(object sender, EventArgs e)
        {
            ShowForm<ShortcutsEditorForm>("Shortcuts Editor");
        }

        /// <summary>
        /// Opens the official website on the default browser.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The event parameters.</param>
        private void WebSiteLinkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            System.Diagnostics.Process.Start("http:\\www.techbits.com.ar");
        }

        /// <summary>
        /// Shows the shortcuts editor for solving conflicts.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The event parameters.</param>
        private void ValidStatusLinkLabel_Click(object sender, EventArgs e)
        {
            if (!ShortcutApl.Instance.GetValidationStatus())
            {
                ShowForm<ShortcutsEditorForm>(ShortcutsEditorForm.WindowTittle);
            }
        }

        /// <summary>
        /// Sets the autocompletion mode.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The event parameters.</param>
        private void ModeLinkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            try
            {
                SetAutoCompletionMode(ShortcutApl.Instance.GetAutoCompletionMode(), false);
            }
            catch (Exception ex)
            {
                _logger.Error(ex);
            }
        }

        /// <summary>
        /// Shows the application.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The event parameters.</param>
        private void TrayNotifyIcon_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            Show();
            WindowState = FormWindowState.Normal;
        }

        /// <summary>
        /// Shows the tips.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The event parameters.</param>
        private void ShowTipsStripMenuItem_Click(object sender, EventArgs e)
        {
            ShowForm<TipsForm>(TipsForm.WindowTittle);
        }

        /// <summary>
        /// Shows the AboutMe form.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The event parameters.</param>
        private void AboutStripMenuItem_Click(object sender, EventArgs e)
        {
            ShowForm<AboutBox>(AboutBox.WindowTittle);
        }

        /// <summary>
        /// Shows the shortcuts editor.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The event parameters.</param>
        private void ShortcutsEditorToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ShowForm<ShortcutsEditorForm>(ShortcutsEditorForm.WindowTittle);
        }

        /// <summary>
        /// Shows the Options window.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The event parameters.</param>
        private void OptionsStripMenuItem_Click(object sender, EventArgs e)
        {
            ShowForm<OptionsForm>(OptionsForm.WindowTittle);
        }

        /// <summary>
        /// Close the application.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The event parameters.</param>
        private void ExitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        /// <summary>
        /// Shows the current date.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The event parameters.</param>
        private void CurrentDateTimer_Tick(object sender, EventArgs e)
        {
            if (Visible)
            {
                CurrentDateLabel.Invoke(new MethodInvoker(() => CurrentDateLabel.Text = DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToLongTimeString()));
            }
        }

        #endregion

        #region "Private Methods"

        /// <summary>
        /// Set the autocompletion mode.
        /// </summary>
        /// <param name="keyword">The keyword.</param>
        /// <param name="showModeMessage">True: shows a message indicating the current mode; False: otherwise.</param>
        private void SetAutoCompletionMode(string keyword, bool showModeMessage)
        {
            try
            {
                // Checks if the user backs from list mode and if so reset the autocompletion mode to the previous mode
                if (keyword.Equals(string.Empty))
                {
                    if (ShortcutApl.Instance.AutoCompletionMode.Equals(AutoCompletionModeEnum.List))
                    {
                        ShortcutApl.Instance.SetAutoCompletionMode(ShortcutApl.Instance.PreviousAutoCompletionMode);
                        LoadAutoCompleteList(AutoCompleteSource.CustomSource);
                    }
                
                    return;
                }

                // Checks for commands
                if (keyword.ToLower().Equals(ShortcutCommands.Exit))
                {
                    Application.Exit();
                    return;
                }                

                // Checks for autocompletion mode
                if (ShortcutApl.Instance.SetAutoCompletionMode(keyword))
                {
                    if (ShortcutApl.Instance.AutoCompletionMode.Equals(AutoCompletionModeEnum.Browser))
                    {
                        LoadAutoCompleteList(AutoCompleteSource.FileSystem);
                    }
                    else
                    {
                        LoadAutoCompleteList(AutoCompleteSource.CustomSource);                        
                    }

                    if (showModeMessage)
                    {
                        ShowMessage(ShortcutApl.Instance.ActiveModeMessage, Color.Turquoise, 1200);
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.Error(ex);
            }
        }

        /// <summary>
        /// Adds the shortcuts associated to the current category to the autocomplete list of the textbox.
        /// </summary>
        /// <param name="autoCompleteSource">The auto Complete Source.</param>
        private void LoadAutoCompleteList(AutoCompleteSource autoCompleteSource)
        {
            try
            {
                InputTextBox.Invoke(new MethodInvoker(() => InputTextBox.AutoCompleteSource = autoCompleteSource));
                                           
                if (autoCompleteSource.Equals(AutoCompleteSource.CustomSource))
                {
                    // Gets the shortcuts for the selected mode
                    var autoCompleteList = ShortcutApl.Instance.GetAutoCompletionList();

                    InputTextBox.Invoke(new MethodInvoker(() => InputTextBox.AutoCompleteCustomSource.Clear()));
                    InputTextBox.Invoke(new MethodInvoker(() => InputTextBox.AutoCompleteCustomSource = autoCompleteList));
                }
            }
            catch (Exception ex)
            {
                _logger.Error(ex);
            }
        }

        /// <summary>
        /// Show a message into the input text box.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <param name="color">The message color.</param>
        /// <param name="timeOut">Show the message for a specified time.</param>
        private void ShowMessage(string message, Color color, int timeOut)
        {         
            try
            {                
                var previousColor = MessageLabel.ForeColor;

                // Set message properties
                MessageLabel.ForeColor = color;
                MessageLabel.Text = message;
                MessageLabel.Visible = true;

                Application.DoEvents();
                Thread.Sleep(timeOut);

                // Restore message properties
                MessageLabel.ForeColor = previousColor;
                MessageLabel.Text = string.Empty;
                MessageLabel.Visible = false;

                InputTextBox.Invoke(new MethodInvoker(() => InputTextBox.Text = string.Empty));
            }
            catch (Exception ex)
            {
                _logger.Error(ex);
            }
        }

        /// <summary>
        /// Applies the settings changes.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The event parameters.</param>
        private void OnAppSettingsChanged(object sender, EventArgs e)
        {
            try
            {
                var newSettings = ApplicationConfiguration.Settings;

                // Apply changes
                Opacity = newSettings.MainWindowOpacity.Equals(0) ? 1.0 : (double)newSettings.MainWindowOpacity / 100;
                if (newSettings.AutoStartWithWindows)
                {
                    WindowsStartUpHelper.Instance.AddApplicationToStartup(ApplicationConfiguration.Name, ApplicationConfiguration.FullPath);
                }
                else
                {
                    WindowsStartUpHelper.Instance.RemoveApplicationFromStartup(ApplicationConfiguration.Name);
                }
            }
            catch (Exception ex)
            {
                _logger.Error(ex);
            }
        }

        /// <summary>
        /// Shows the validation status of the shortcuts.
        /// </summary>
        private void ShowValidationStatus()
        {
            if (ShortcutApl.Instance.GetValidationStatus())
            {
                ValidStatusLinkLabel.Invoke(new MethodInvoker(() => ValidStatusLinkLabel.Image = Resources.ValidStatus));
                HelpToolTip.SetToolTip(ValidStatusLinkLabel, "All shortcuts are valid");
            }
            else
            {
                ValidStatusLinkLabel.Invoke(new MethodInvoker(() => ValidStatusLinkLabel.Image = Resources.ErrorStatus));
                HelpToolTip.SetToolTip(ValidStatusLinkLabel, "Some shortcuts are invalid. Click here to edit conclicts!");
            }
        }

        /// <summary>
        /// Shows a form.
        /// </summary>
        /// <param name="formWindowTittle">The form window tittle.</param>
        /// <typeparam name="T">The form type.</typeparam>
        private static void ShowForm<T>(string formWindowTittle) where T : Form, new()
        {
            try
            {
                if (WindowsHelper.FindWindow(formWindowTittle) == 0)
                {
                    var form = new T();
                    form.Show();
                }
            }
            catch (Exception ex)
            {
                _logger.Error(ex);
            }
        }

        #endregion
    }
}